class FreightCalculator {
  /**
   * 初始化运费计算器
   * @param {Object} province - 省份信息
   * @param {Array} rates - 费率段数组
   */
  constructor(province, rates) {
    this.province = province;
    this.rates = rates || [];
    this.calcType = province.calc_type;
    
    // 验证并排序费率段
    this.validateRates();
    this.sortRates();
  }
  
  /**
   * 验证费率段配置的有效性
   */
  validateRates() {
    if (this.rates.length === 0) {
      throw new Error(`省份"${this.province.name}"未配置费率段`);
    }
    
    // 检查是否有重复的排序号
    const sortNums = new Set();
    this.rates.forEach(rate => {
      if (sortNums.has(rate.sort_num)) {
        throw new Error(`省份"${this.province.name}"存在重复的排序号: ${rate.sort_num}`);
      }
      sortNums.add(rate.sort_num);
    });
    
    // 检查重量段是否重叠（允许相邻，如0-1和1-2）
    for (let i = 1; i < this.rates.length; i++) {
      const prevRate = this.rates[i - 1];
      const currRate = this.rates[i];
      
      // 处理无上限段
      if (prevRate.weight_max === null) {
        throw new Error(`省份"${this.province.name}"的无上限段不能放在中间`);
      }
      
      // 检查真正的重叠（当前段的最小值小于上一段的最大值）
      if (currRate.weight_min < prevRate.weight_max) {
        throw new Error(
          `省份"${this.province.name}"重量段重叠: ${prevRate.weight_min}-${prevRate.weight_max} 与 ${currRate.weight_min}-${currRate.weight_max}`
        );
      }
    }
    
    // 检查无上限段是否在最后
    const lastRate = this.rates[this.rates.length - 1];
    const hasOtherNullMax = this.rates.slice(0, -1).some(rate => rate.weight_max === null);
    
    if (hasOtherNullMax) {
      throw new Error(`省份"${this.province.name}"只能有一个无上限段，且必须在最后`);
    }
  }
  
  /**
   * 按排序号对费率段进行排序
   */
  sortRates() {
    this.rates.sort((a, b) => a.sort_num - b.sort_num);
  }
  
  /**
   * 根据重量匹配对应的费率段
   * @param {number} weight - 重量(kg)
   * @returns {Object} 匹配的费率段
   */
  getMatchedRate(weight) {
    for (const rate of this.rates) {
      // 处理无上限段
      if (rate.weight_max === null) {
        if (weight >= rate.weight_min) {
          return rate;
        }
        continue;
      }
      
      // 左闭右闭区间：0≤weight≤1 匹配0-1段
      if (weight >= rate.weight_min && weight <= rate.weight_max) {
        return rate;
      }
    }
    
    throw new Error(`重量${weight}kg在省份"${this.province.name}"中无匹配的费率段`);
  }
  
  /**
   * 计算运费
   * @param {number} weight - 重量(kg)
   * @param {number} [pieceCount=1] - 件数，按件计费时使用
   * @returns {number} 计算后的运费
   */
  calculate(weight, pieceCount = 1) {
    if (weight < 0) throw new Error('重量不能为负数');
    if (pieceCount < 1) throw new Error('件数不能小于1');
    
    // 根据不同计费方式计算
    switch (this.calcType) {
      case 'weight_step':
        return this.calculateByWeightStep(weight);
      case 'fixed_add':
        return this.calculateByFixedAdd(weight);
      case 'piece':
        return this.calculateByPiece(pieceCount);
      default:
        throw new Error(`不支持的计费方式: ${this.calcType}`);
    }
  }
  
  /**
   * 按重量阶梯计费
   * @param {number} weight - 重量(kg)
   * @returns {number} 运费
   */
  calculateByWeightStep(weight) {
    const matchedRate = this.getMatchedRate(weight);
    return parseFloat((matchedRate.base_fee + weight * matchedRate.rate).toFixed(2));
  }
  
  /**
   * 按固定续重计费（首重+续重）
   * @param {number} weight - 重量(kg)
   * @returns {number} 运费
   */
  calculateByFixedAdd(weight) {
    // 首重段应该是排序号为0的段
    const firstRate = this.rates.find(rate => rate.sort_num === 0);
    if (!firstRate) {
      throw new Error(`省份"${this.province.name}"未配置首重段（排序号0）`);
    }
    
    // 续重段应该是排序号为1的段
    const addRate = this.rates.find(rate => rate.sort_num === 1);
    if (!addRate) {
      throw new Error(`省份"${this.province.name}"未配置续重段（排序号1）`);
    }
    
    // 首重重量
    const firstWeight = firstRate.weight_max;
    
    if (weight <= firstWeight) {
      // 不超过首重
      return parseFloat(firstRate.base_fee.toFixed(2));
    } else {
      // 超过首重，计算续重
      const extraWeight = weight - firstWeight;
      return parseFloat((firstRate.base_fee + extraWeight * addRate.rate).toFixed(2));
    }
  }
  
  /**
   * 按件计费
   * @param {number} pieceCount - 件数
   * @returns {number} 运费
   */
  calculateByPiece(pieceCount) {
    const rate = this.rates[0]; // 按件计费只需要一个费率段
    return parseFloat((rate.base_fee + pieceCount * rate.rate).toFixed(2));
  }
}

module.exports = FreightCalculator;
